package zdream.control.world;

import java.util.ArrayList;
import java.util.List;

import zdream.control.region.Region;
import zdream.control.region.Room;
import zdream.utils.math.MathUtils;
import zdream.utils.math.Rectangle;

/**
 * @author Zdream
 * @since 0.0.1
 * @date 2022-06-01 (created)
 */
public class LevelCamera {
	private final LevelWorld world;

	public LevelCamera(LevelWorld world) {
		this.world = world;

		view.withWidth(Region.BLOCK_WIDTH).withHeight(Region.BLOCK_HEIGHT);
	}

	/* **********
	 * 世界镜头 *
	 ********** */
	/**
	 * 查看该世界的镜头, 一般长宽为 25 x 14
	 * 这个锁定的是人物位置.
	 *
	 * 这里会根据主人公的移动, 来移动这个照相机的位置.
	 * 当前只处理一个焦点的情况. 多个焦点需要后续修改 TODO
	 *
	 * <li>在 room 切换时, 主机把这个列表清空. 切换结束别忘了加回来
	 * </li>
	 */
	public final List<MFoe> focus = new ArrayList<>();

	/**
	 * 真实的屏幕上区域的范围. 已计算振动
	 * (以当前房间左下角为坐标系, 单位: 块)
	 */
	public final Rectangle view = new Rectangle();

	/**
	 * 振动造成的位移
	 */
	public float vibrateX, vibrateY;

	public void focusToFoeOnly(MFoe foe) {
		focus.clear();
		focus.add(foe);
		refresh();
	}

	/**
	 * camera 跟着角色走
	 */
	public void tick(Ticker ticker) {
		refresh();
		updateCamera();
	}

	public void setCenterPointAndFix(float x, float y) {
		float viewWidth2 = view.width / 2;
		float viewHeight2 = view.height / 2;
		Room room = world.currentRoom;

		float leftX = MathUtils.clamp(x - viewWidth2, 0, room.width - view.width);
		float bottomY = MathUtils.clamp(y - viewHeight2, 0, room.height - view.height);
		view.withX(leftX).withY(bottomY);
	}

	public void setLeftBottomPointAt(float x, float y) {
		Room room = world.currentRoom;

		float leftX = MathUtils.clamp(x, 0, room.width - view.width);
		float bottomY = MathUtils.clamp(y, 0, room.height - view.height);
		view.withX(leftX).withY(bottomY);
	}

	public void setLeftBottomPointXNotRestrict(float x) {
		view.withX(x);
	}

	public void setLeftBottomPointYNotRestrict(float y) {
		view.withY(y);
	}

	private void calcCenterPointWithPlayer() {
		if (this.focus.size() != 1) {
			throw new RuntimeException("现在 LevelCamera 不支持处理同时聚焦 " + this.focus.size() + " 个 Foes");
		}

		MFoe foe = this.focus.get(0);
		setCenterPointAndFix(foe.anchorX, foe.anchorY);
	}

	private void updateCamera() {
		// 计算场地的振动, 加到 view 上去
		view.x += vibrateX;
		view.y += vibrateY;
	}

	/**
	 * 根据当前配置刷新相机的范围.
	 * 如果 {@link #focus} 里面有内容, 跟着 {@link #focus} 中 {@link MFoe} 的位置
	 * 修改 {@link #view} 的范围数据.
	 */
	public void refresh() {
		if (!this.focus.isEmpty()) {
			calcCenterPointWithPlayer();
		}
	}
}